home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Internet / WWW / swish.11 / src / index.c < prev    next >
C/C++ Source or Header  |  1995-03-13  |  28KB  |  1,009 lines

  1. /*
  2. ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
  3. ** All Rights Reserved.
  4. ** Kevin Hughes, kevinh@eit.com 
  5. ** 3/11/94
  6. */
  7.  
  8. #include "swish.h"
  9. #include "index.h"
  10.  
  11. /* Recursively goes into a directory and calls the word-indexing
  12. ** functions for each file that's found.
  13. */
  14.  
  15. void indexadir(dir)
  16.      char *dir;
  17. {
  18.         int badfile;
  19.         DIR *dfd;
  20. #ifdef NEXTSTEP
  21.         struct direct *dp;
  22. #else
  23.         struct dirent *dp;
  24. #endif
  25.     static char s[MAXFILELEN], title[MAXSTRLEN];
  26.         struct sortentry *sortfilelist, *sortdirlist;
  27.         struct swline *tmplist;
  28.  
  29.         sortfilelist = sortdirlist = NULL;
  30.  
  31.     if (islink(dir) && !followsymlinks)
  32.         return;
  33.  
  34.         if (dir[strlen(dir) - 1] == '/')
  35.                 dir[strlen(dir) - 1] = '\0';
  36.  
  37.         if ((dfd = opendir(dir)) == NULL)
  38.                 return;
  39.  
  40.         while ((dp = readdir(dfd)) != NULL && dirconlist != NULL) {
  41.                 badfile = 0;
  42.                 tmplist = dirconlist;
  43.                 while (tmplist != NULL) {
  44.                         if (lstrstr(dp->d_name, tmplist->line)) {
  45.                                 badfile = 1;
  46.                                 break;
  47.                         }
  48.                         tmplist = tmplist->next;
  49.                 }
  50.                 if (badfile)
  51.                         return;
  52.     }
  53.     closedir(dfd);
  54.     dfd = opendir(dir);
  55.  
  56.         while ((dp = readdir(dfd)) != NULL) {
  57.  
  58.                 if ((dp->d_name)[0] == '.')
  59.                         continue;
  60.         if (islink(dp->d_name) && !followsymlinks)
  61.             continue;
  62.  
  63.                 badfile = 0;
  64.                 tmplist = fileislist;
  65.                 while (tmplist != NULL) {
  66.                         if (!strcmp(dp->d_name, tmplist->line)) {
  67.                                 badfile = 1;
  68.                                 break;
  69.                         }
  70.                         tmplist = tmplist->next;
  71.                 }
  72.                 if (badfile)
  73.                         continue;
  74.  
  75.                 badfile = 0;
  76.                 tmplist = fileconlist;
  77.                 while (tmplist != NULL) {
  78.                         if (lstrstr(dp->d_name, tmplist->line)) {
  79.                                 badfile = 1;
  80.                                 break;
  81.                         }
  82.                         tmplist = tmplist->next;
  83.                 }
  84.                 if (badfile)
  85.                         continue;
  86.  
  87.                 sprintf(s, "%s%s%s", dir, dir[strlen(dir) - 1] == '/' ?
  88.                 "" : "/", dp->d_name);
  89.         if (islink(s) && !followsymlinks)
  90.             continue;
  91.  
  92.                 badfile = 0;
  93.                 tmplist = pathconlist;
  94.                 while (tmplist != NULL) {
  95.                         if (lstrstr(s, tmplist->line)) {
  96.                                 badfile = 1;
  97.                                 break;
  98.                         }
  99.                         tmplist = tmplist->next;
  100.                 }
  101.                 if (badfile)
  102.                         continue;
  103.  
  104.                 if (!isdirectory(s)) {
  105.  
  106.             if (!isoksuffix(dp->d_name, suffixlist))
  107.                 continue;
  108.  
  109.                         if (ishtml(s)) {
  110.                                 strcpy(title, (char *) parsetitle(s));
  111.                                 if (!isoktitle(title))
  112.                                         continue;
  113.                         }
  114.                         else {
  115.                                 if (strrchr(s, '/') != NULL)
  116.                                         strcpy(title, strrchr(s, '/') + 1);
  117.                                 else
  118.                                         strcpy(title, s);
  119.                         }
  120.                         sortfilelist = (struct sortentry *)
  121.                         addsortentry(sortfilelist, s, title);
  122.                 }
  123.                 else {
  124.                         sortdirlist = (struct sortentry *)
  125.                         addsortentry(sortdirlist, s, s);
  126.                 }
  127.         }
  128.  
  129.         closedir(dfd);
  130.  
  131.         printfiles(sortfilelist);
  132.         printdirs(sortdirlist);
  133. }
  134.  
  135. /* Calls the word-indexing function for a single file.
  136. */
  137.  
  138. void indexafile(path)
  139.      char *path;
  140. {
  141.         int badfile;
  142.         char *t, title[MAXSTRLEN];
  143.         struct sortentry *fileentry;
  144.         struct swline *tmplist;
  145.  
  146.     if (islink(path) && !followsymlinks)
  147.         return;
  148.  
  149.         if (path[strlen(path) - 1] == '/')
  150.                 path[strlen(path) - 1] = '\0';
  151.  
  152.         badfile = 0;
  153.         tmplist = fileislist;
  154.         while (tmplist != NULL) {
  155.                 if (!strcmp(path, tmplist->line)) {
  156.                         badfile = 1;
  157.                         break;
  158.                 }
  159.                 tmplist = tmplist->next;
  160.         }
  161.         if (badfile)
  162.                 return;
  163.  
  164.         badfile = 0;
  165.         tmplist = fileconlist;
  166.         while (tmplist != NULL) {
  167.                 if (lstrstr(path, tmplist->line)) {
  168.                         badfile = 1;
  169.                         break;
  170.                 }
  171.                 tmplist = tmplist->next;
  172.         }
  173.         if (badfile)
  174.                 return;
  175.  
  176.         badfile = 0;
  177.         tmplist = pathconlist;
  178.         while (tmplist != NULL) {
  179.                 if (lstrstr(path, tmplist->line)) {
  180.                         badfile = 1;
  181.                         break;
  182.                 }
  183.                 tmplist = tmplist->next;
  184.         }
  185.         if (badfile)
  186.                 return;
  187.  
  188.     if (!isoksuffix(path, suffixlist))
  189.         return;
  190.  
  191.         if (ishtml(path)) {
  192.                 strcpy(title, (char *) parsetitle(path));
  193.                 if (!isoktitle(title))
  194.                         return;
  195.         }
  196.         else {
  197.                 if ((t = strrchr(path, '/')) != NULL)
  198.                         strcpy(title, t + 1);
  199.                 else
  200.                         strcpy(title, path);
  201.         }
  202.  
  203.         fileentry = (struct sortentry *) emalloc(sizeof(struct sortentry));
  204.         fileentry->filename = (char *) mystrdup(path);
  205.         fileentry->title = (char *) mystrdup(title);
  206.         fileentry->left = fileentry->right = NULL;
  207.  
  208.         printfiles(fileentry);
  209. }
  210.  
  211. /* Indexes the words in the tree of files in alphabetical order.
  212. */
  213.  
  214. void printfiles(e)
  215.      struct sortentry *e;
  216. {
  217.         int wordcount;
  218.     char *s;
  219.  
  220.         if (e != NULL) {
  221.                 printfiles(e->left);
  222.                 if (verbose == 3) {
  223.             if ((s = (char *) strrchr(e->filename, '/')) == NULL)
  224.                             printf("  %s", e->filename);
  225.             else
  226.                             printf("  %s", s + 1);
  227.         }
  228.                 wordcount = countwords(e->filename, e->title);
  229.                 if (verbose == 3) {
  230.                         if (wordcount)
  231.                                 printf(" (%d words)\n", wordcount);
  232.                         else
  233.                                 printf(" (no words)\n");
  234.                         fflush(stdout);
  235.                 }
  236.         free(e->filename);
  237.         free(e->title);
  238.                 printfiles(e->right);
  239.         free(e);
  240.         }
  241. }
  242.  
  243. /* Prints out the directory names as things are getting indexed.
  244. ** Calls indexadir() so directories in the tree are indexed,
  245. ** in alphabetical order...
  246. */
  247.  
  248. void printdirs(e)
  249.      struct sortentry *e;
  250. {
  251.         if (e != NULL) {
  252.                 printdirs(e->left);
  253.                 if (verbose == 3)
  254.                         printf("\nIn dir \"%s\":\n", e->filename);
  255.                 else if (verbose == 2)
  256.                         printf("Checking dir \"%s\"...\n", e->filename);
  257.                 indexadir(e->filename);
  258.         free(e->filename);
  259.         free(e->title);
  260.                 printdirs(e->right);
  261.         free(e);
  262.         }
  263. }
  264.  
  265. /* Stores file names in alphabetical order so they can be
  266. ** indexed alphabetically. No big whoop.
  267. */
  268.  
  269. struct sortentry *addsortentry(e, filename, title)
  270.      struct sortentry *e;
  271.      char *filename;
  272.      char *title;
  273. {
  274.         if (e == NULL) {
  275.                 e = (struct sortentry *) emalloc(sizeof(struct sortentry));
  276.                 e->filename = (char *) mystrdup(filename);
  277.                 e->title = (char *) mystrdup(title);
  278.                 e->left = e->right = NULL;
  279.         }
  280.         else {
  281.                 if (strcmp(e->filename, filename) > 0)
  282.                         e->left = (struct sortentry *)
  283.                         addsortentry(e->left, filename, title);
  284.                 else
  285.                         e->right = (struct sortentry *)
  286.                         addsortentry(e->right, filename, title);
  287.         }
  288.  
  289.         return e;
  290. }
  291.  
  292. /* Adds a word to the master index tree.
  293. */
  294.  
  295. struct entry *addentry(e, word, filenum, emphasized, structure)
  296.      struct entry *e;
  297.      char *word;
  298.      int filenum;
  299.      int emphasized;
  300.      int structure;
  301. {
  302.         int isbigger;
  303.         struct location *tp, *oldtp;
  304.  
  305.         if (e == NULL) {
  306.                 e = (struct entry *) emalloc(sizeof(struct entry));
  307.                 e->word = (char *) mystrdup(word);
  308.                 e->tfrequency = 1;
  309.                 e->locationlist = (struct location *)
  310.                 emalloc(sizeof(struct location));
  311.                 e->locationlist->filenum = filenum;
  312.                 e->locationlist->frequency = 1;
  313.                 e->locationlist->emphasized = emphasized;
  314.                 e->locationlist->structure = structure;
  315.                 e->locationlist->next = NULL;
  316.                 e->left = e->right = NULL;
  317.         totalwords++;
  318.         }
  319.         else {
  320.                 isbigger = wordcompare(e->word, word);
  321.                 if (isbigger == 0) {
  322.                         tp = e->locationlist;
  323.                         while (tp != NULL && tp->filenum != filenum) {
  324.                                 oldtp = tp;
  325.                                 tp = tp->next;
  326.                         }
  327.                         if (tp == NULL) {
  328.                                 tp = (struct location *) emalloc(sizeof(struct
  329.                                 location));
  330.                                 tp->filenum = filenum;
  331.                                 tp->frequency = 1;
  332.                                 tp->emphasized = emphasized;
  333.                                 tp->structure = structure;
  334.                                 tp->next = NULL;
  335.                                 oldtp->next = tp;
  336.                                 if (!emphasized)
  337.                                         e->tfrequency = e->tfrequency + 1;
  338.                         }
  339.                         else {
  340.                                 if (tp->filenum == filenum) {
  341.                                         tp->frequency = tp->frequency + 1;
  342.                     if (emphasized)
  343.                         tp->emphasized =
  344.                         tp->emphasized + 1;
  345.                     tp->structure |= structure;
  346.                 }
  347.                         }
  348.                 }
  349.                 else if (isbigger > 0)
  350.                         e->left = (struct entry *)
  351.                         addentry(e->left, word, filenum, emphasized,
  352.             structure);
  353.                 else
  354.                         e->right = (struct entry *)
  355.                         addentry(e->right, word, filenum, emphasized,
  356.             structure);
  357.         }
  358.  
  359.         return e;
  360. }
  361.  
  362. /* Adds a file to the master list of files and file numbers.
  363. */
  364.  
  365. struct file *addtofilelist(filep, filename, title, size)
  366.      struct file *filep;
  367.      char *filename;
  368.      char *title;
  369.      int size;
  370. {
  371.         struct file *newnode;
  372.         static struct file *filelistp = NULL;
  373.  
  374.         newnode = (struct file *) emalloc(sizeof(struct file));
  375.         newnode->filename = (char *) mystrdup(filename);
  376.         newnode->title = (char *) mystrdup(title);
  377.         newnode->size = size;
  378.         newnode->next = NULL;
  379.  
  380.         if (filep == NULL)
  381.                 filep = newnode;
  382.         else if (filelistp != NULL)
  383.                 filelistp->next = newnode;
  384.  
  385.         filelistp = newnode;
  386.  
  387.         return filep;
  388. }
  389.  
  390. /* Just goes through the master list of files and
  391. ** counts 'em.
  392. */
  393.  
  394. int getfilecount(filep)
  395.      struct file *filep;
  396. {
  397.         int i;
  398.  
  399.         for (i = 0; filep != NULL; filep = filep->next)
  400.                 i++;
  401.  
  402.         return i;
  403. }
  404.  
  405. /* Returns the nicely formatted date.
  406. */
  407.  
  408. char *getthedate()
  409. {
  410.     static char date[MAXSTRLEN];
  411.     time_t time;
  412.  
  413.     time = (time_t) getthetime();
  414.     strftime(date, MAXSTRLEN, "%x %X", (struct tm *) localtime(&time));
  415.     strftime(date, MAXSTRLEN, "%d/%m/%y %H:%M:%S %Z",
  416.     (struct tm *) localtime(&time));
  417.  
  418.     return date;
  419. }
  420.  
  421. /* Indexes all the words in a file and adds the appropriate information
  422. ** to the appropriate structures.
  423. */
  424.  
  425. int countwords(filename, title)
  426.      char *filename;
  427.      char *title;
  428. {
  429.         int c, i, j, inword, ftotalwords, emphasized, structure;
  430.         static int filenum;
  431.         char word[MAXWORDLEN], tag[MAXSTRLEN];
  432.         FILE *fp;
  433.  
  434.         if ((fp = fopen(filename, "r")) == NULL)
  435.                 return 0;
  436.  
  437.         ftotalwords = 0;
  438.         if (isoksuffix(filename, nocontentslist) && nocontentslist != NULL) {
  439.                 filelist = addtofilelist(filelist, filename,
  440.                 title, getsize(filename));
  441.                 fclose(fp);
  442.                 filenum++;
  443.                 if (!(filenum % 128))
  444.                         filenum++;
  445.                 addtofwordtotals(filenum, 100);
  446.                 return (countwordstr(title, filenum, 0));
  447.         }
  448.  
  449.         filelist = addtofilelist(filelist, filename, title, getsize(filename));
  450.         filenum++;
  451.         if (!(filenum % 128))
  452.                 filenum++;
  453.  
  454.     c = 1;
  455.         i = j = 0;
  456.         inword = 0;
  457.         emphasized = 0;
  458.     structure = 1;
  459.  
  460.         while (c != EOF && (c = fgetc(fp)) != EOF) {
  461.                 if (!inword) {
  462.                         if (iswordchar(c)) {
  463.                                 i = 0;
  464.                                 word[i++] = c;
  465.                 if (i == MAXWORDLEN)
  466.                     i--;
  467.                                 inword = 1;
  468.                         }
  469.                 }
  470.                 else if (inword) {
  471.                         if (!iswordchar(c)) {
  472.                                 word[i++] = '\0';
  473.                 if (i == MAXWORDLEN)
  474.                     word[--i] = '\0';
  475.                                 for (i = 0; word[i]; i++)
  476.                                         word[i] = tolower(word[i]);
  477.                 i = 0;
  478.                                 if (isokword(word))
  479.                     strcpy(word, (char *)
  480.                     convertentities(word));
  481.  
  482. /* Sorry, have to do isokword() twice to filter out converted strings! */
  483.  
  484.                                 if (hasokchars(word) && isokword(word)) {
  485. #ifdef DEBUG
  486. printf("    %s %d\n", word, structure);
  487. #endif
  488.                                         entrylist = (struct entry *)
  489.                                         addentry(entrylist, word,
  490.                                         filenum, emphasized, structure);
  491.                                         ftotalwords++;
  492.                                 }
  493.                                 inword = 0;
  494.                         }
  495.                         else {
  496.                                 word[i++] = c;
  497.                 if (i == MAXWORDLEN)
  498.                     i--;
  499.             }
  500.         }
  501.                 if (c == '<' && !INDEXTAGS) {
  502.             j = 0;
  503.             while ((c = fgetc(fp)) != EOF) {
  504.                 tag[j++] = c;
  505.                 if (j == MAXSTRLEN)
  506.                     j--;
  507.                             if (c == '>') {
  508.                     if (j)
  509.                         tag[--j] = '\0';
  510.                     else
  511.                         tag[j] = '\0';
  512. #ifdef DEBUG
  513. printf("t: %s\n", tag);
  514. #endif
  515.                     structure = getstructure(tag,
  516.                     structure);
  517. #ifdef DEBUG
  518. printf("s: %d\n", structure);
  519. #endif
  520.                     if (tag[0] == '!')
  521.                         ftotalwords +=
  522.                         parsecomment(tag,
  523.                         filenum, structure);
  524.                     if ((structure & IN_HEADER) ||
  525.                     (structure & IN_TITLE))
  526.                         emphasized = 5;
  527.                     else
  528.                         emphasized = 0;
  529.  
  530.                     break;
  531.                 }
  532.             }
  533.                 }
  534.         }
  535.  
  536.         fclose(fp);
  537.  
  538.         addtofwordtotals(filenum, ftotalwords);
  539.         return ftotalwords;
  540. }
  541.  
  542. /* Indexes the words in a string, such as a file name or an
  543. ** HTML title.
  544. */
  545.  
  546. int countwordstr(s, filenum, emphasized)
  547.      char *s;
  548.      int filenum;
  549.      int emphasized;
  550. {
  551.         int i, j, inword, wordcount;
  552.         char c, word[MAXWORDLEN], tmpstr[MAXFILELEN];
  553.  
  554.         sprintf(tmpstr, "%s ", s);
  555.         for (j = inword = wordcount = 0; (c = tmpstr[j]) != '\0'; j++) {
  556.                 if (!inword) {
  557.                         if (iswordchar(c)) {
  558.                                 i = 0;
  559.                                 word[i++] = c;
  560.                 if (i == MAXWORDLEN)
  561.                     i--;
  562.                                 inword = 1;
  563.                         }
  564.                 }
  565.                 else {
  566.                         if (!iswordchar(c)) {
  567.                                 wordcount++;
  568.                                 word[i] = '\0';
  569.                                 for (i = 0; word[i]; i++)
  570.                                         word[i] = tolower(word[i]);
  571.                                 if (isokword(word))
  572.                     strcpy(word, (char *)
  573.                     convertentities(word));
  574.                                 if (hasokchars(word) && isokword(word))
  575.                                         entrylist = (struct entry *)
  576.                                         addentry(entrylist, word,
  577.                                         filenum, emphasized, IN_FILE);
  578.                                 inword = 0;
  579.                         }
  580.                         else {
  581.                                 word[i++] = c;
  582.                 if (i == MAXWORDLEN)
  583.                     i--;
  584.             }
  585.                 }
  586.         }
  587.  
  588.         return wordcount;
  589. }
  590.  
  591. /* This returns the value corresponding to the HTML structures
  592. ** a word is in.
  593. */
  594.  
  595. int getstructure(tag, structure)
  596.      char *tag;
  597.      int structure;
  598. {
  599.     int len;
  600.  
  601.     len = strlen(tag);
  602.     if (lstrstr(tag, "/title") && len == 6)
  603.         structure &= ~IN_TITLE;
  604.     else if (lstrstr(tag, "title") && len == 5)
  605.         structure |= IN_TITLE;
  606.     else if (lstrstr(tag, "/head") && len == 5)
  607.         structure &= ~IN_HEAD;
  608.     else if (lstrstr(tag, "head") && len == 4)
  609.         structure |= IN_HEAD;
  610.     else if (lstrstr(tag, "/body") && len == 5)
  611.         structure &= ~IN_BODY;
  612.     else if (lstrstr(tag, "body") && len == 4)
  613.         structure |= IN_BODY;
  614.     else if (tag[0] == '/' && tolower(tag[1]) == 'h' && isdigit(tag[2]))
  615.         structure &= ~IN_HEADER;
  616.     else if (tolower(tag[0]) == 'h' && isdigit(tag[1]))
  617.         structure |= IN_HEADER;
  618.     else if (lstrstr(tag, "/em") || lstrstr(tag, "/strong"))
  619.         structure &= ~IN_EMPHASIZED;
  620.     else if (lstrstr(tag, "em") || lstrstr(tag, "strong"))
  621.         structure |= IN_EMPHASIZED;
  622.     else if ((tolower(tag[0]) == 'b' || tolower(tag[0]) == 'i') &&
  623.     len == 1)
  624.         structure |= IN_EMPHASIZED;
  625.     else if (tag[0] == '/' && tag[2] == '\0' && (tolower(tag[1]) == 'b' ||
  626.     tolower(tag[1]) == 'i'))
  627.         structure &= ~IN_EMPHASIZED;
  628.  
  629.     return structure;
  630. }
  631.  
  632. /* Parses the words in a comment.
  633. */
  634.  
  635. int parsecomment(tag, filenum, structure)
  636.      char *tag;
  637.      int filenum;
  638.      int structure;
  639. {
  640.     int i, j, inword, wordcount, emphasized;
  641.     char c, word[MAXWORDLEN];
  642.  
  643.     if (EMPHASIZECOMMENTS)
  644.         emphasized = 5;
  645.     else
  646.         emphasized = 0;
  647.     structure |= IN_COMMENTS;
  648.         for (j = 3, inword = wordcount = 0; (c = tag[j]) != '\0'; j++) {
  649.                 if (!inword) {
  650.                         if (iswordchar(c)) {
  651.                                 i = 0;
  652.                                 word[i++] = c;
  653.                 if (i == MAXWORDLEN)
  654.                     i--;
  655.                                 inword = 1;
  656.                         }
  657.                 }
  658.                 else {
  659.                         if (!iswordchar(c)) {
  660.                                 wordcount++;
  661.                                 word[i] = '\0';
  662.                                 for (i = 0; word[i]; i++)
  663.                                         word[i] = tolower(word[i]);
  664.                                 if (isokword(word))
  665.                     strcpy(word, (char *)
  666.                     convertentities(word));
  667.                                 if (hasokchars(word) && isokword(word))
  668.                                         entrylist = (struct entry *)
  669.                                         addentry(entrylist, word,
  670.                                         filenum, emphasized, structure);
  671.                                 inword = 0;
  672.                         }
  673.                         else {
  674.                                 word[i++] = c;
  675.                 if (i == MAXWORDLEN)
  676.                     i--;
  677.             }
  678.                 }
  679.         }
  680.  
  681.         return wordcount;
  682. }
  683.  
  684. /* Removes words that occur in over _plimit_ percent of the files and
  685. ** that occur in over _flimit_ files (marks them as stopwords, that is).
  686. */
  687.  
  688. int removestops(ep, totalfiles, plimit, flimit)
  689.      struct entry *ep;
  690.      int totalfiles;
  691.      int plimit;
  692.      int flimit;
  693. {
  694.     int percent, wordfilecount, stopwords;
  695.         struct location *lp;
  696.  
  697.     stopwords = 0;
  698.     if (ep != NULL) {
  699.         stopwords += removestops(ep->left, totalfiles, plimit, flimit);
  700.                 lp = ep->locationlist;
  701.         wordfilecount = 0;
  702.                 while (lp != NULL) {
  703.             wordfilecount++;
  704.                         lp = lp->next;
  705.                 }
  706.         percent = ((float) wordfilecount / (float) totalfiles) * 100.0;
  707.         if (percent >= plimit && wordfilecount >= flimit) {
  708.             addstophash(ep->word);
  709.             stopwords++;
  710.         }
  711.         stopwords += removestops(ep->right, totalfiles, plimit, flimit);
  712.     }
  713.     return stopwords;
  714. }
  715.  
  716. /* This is somewhat similar to the rank calculation algorithm
  717. ** from WAIS (I think). Any suggestions for improvements?
  718. ** Note that ranks can't be smaller than 1, emphasized words
  719. ** (words in titles, headers) have ranks multiplied by at least 5
  720. ** (just a guess), and ranks divisible by 128 are bumped up by one
  721. ** (to make the compression scheme with with '\0' as a line delimiter
  722. ** work). Fudging with the ranks doesn't seem to make much difference.
  723. */
  724.  
  725. int getrank(freq, tfreq, words, emphasized)
  726.      int freq;
  727.      int tfreq;
  728.      int words;
  729.      int emphasized;
  730. {
  731.         float d, e, f;
  732.         int tmprank;
  733.         char rankstr[MAXSTRLEN];
  734.  
  735.         if (freq < 5)
  736.                 freq = 5;
  737.         d = 1.0 / (double) tfreq;
  738.         e = ((log((double) freq) + 10.0) * d) / words;
  739.         f = e * 10000.0;
  740.  
  741.         sprintf(rankstr, "%f", f);
  742.         tmprank = atoi(rankstr);
  743.         if (tmprank <= 0)
  744.                 tmprank = 1;
  745.         if (emphasized)
  746.                 tmprank *= emphasized;
  747.         if (!(tmprank % 128))
  748.                 tmprank++;
  749.  
  750.         return tmprank;
  751. }
  752.  
  753. /* Prints the index information at the head of index files.
  754. */
  755.  
  756. void printheader(fp, filename, totalwords, totalfiles)
  757.      FILE *fp;
  758.      char *filename;
  759.      int totalwords;
  760.      int totalfiles;
  761. {
  762.     char *c;
  763.  
  764.     c = (char *) strrchr(filename, '/');
  765.  
  766.     fprintf(fp, "%s\n", INDEXHEADER);
  767.     fprintf(fp, "# Name: %s\n", (indexn[0] == '\0') ? "(no name)" :
  768.     indexn);
  769.     fprintf(fp, "# Saved as: %s\n", (c == NULL && c + 1 != '\0') ?
  770.         filename : c + 1);
  771.     fprintf(fp, "# Counts: ");
  772.     if (totalwords)
  773.         fprintf(fp, "%d words%s", totalwords, (totalfiles) ? ", " : "");
  774.     if (totalfiles)
  775.         fprintf(fp, "%d files", totalfiles);
  776.     fprintf(fp, "\n");
  777.     fprintf(fp, "# Indexed on: %s\n", getthedate());
  778.     fprintf(fp, "# Description: %s\n", (indexd[0] == '\0') ?
  779.     "(no description)" : indexd);
  780.     fprintf(fp, "# Pointer: %s\n", (indexp[0] == '\0') ?
  781.     "(no pointer)" : indexp);
  782.     fprintf(fp, "# Maintained by: %s\n", (indexa[0] == '\0') ?
  783.     "(no maintainer)" : indexa);
  784. }
  785.  
  786. /* Print the index entries that hold the word, rank, and other information.
  787. */
  788.  
  789. void printindex(ep, fp)
  790.      struct entry *ep;
  791.      FILE *fp;
  792. {
  793.         int i, rank;
  794.         struct location *lp;
  795.  
  796.         if (ep != NULL) {
  797.                 printindex(ep->left, fp);
  798.         if (!isstopword(ep->word)) {
  799.  
  800.             for (i = 0; indexchars[i] != '\0'; i++)
  801.                 if ((ep->word)[0] == indexchars[i] &&
  802.                 !offsets[i])
  803.                     offsets[i] = ftell(fp);
  804.  
  805.                     fprintf(fp, "%s:", ep->word);
  806.             lp = ep->locationlist;
  807.             while (lp != NULL) {
  808.                 compress(lp->filenum, fp);
  809.                 rank = getrank(lp->frequency, ep->tfrequency,
  810.                 gettotalwords(lp->filenum), lp->emphasized);
  811.                 compress(rank, fp);
  812.                 compress(lp->structure, fp);
  813.                 lp = lp->next;
  814.                     }
  815.                     fputc(0, fp);
  816.  
  817.         }
  818.                 printindex(ep->right, fp);
  819.         }
  820. }
  821.  
  822. /* Prints the list of stopwords into the index file.
  823. */
  824.  
  825. void printstopwords(fp)
  826.      FILE *fp;
  827. {
  828.     int hashval;
  829.     struct swline *sp;
  830.  
  831.     offsets[STOPWORDPOS] = ftell(fp);
  832.     for (hashval = 0; hashval < HASHSIZE; hashval++) {
  833.             sp = hashstoplist[hashval];
  834.         while (sp != NULL) {
  835.             fprintf(fp, "%s ", sp->line);
  836.             sp = sp->next;
  837.         }
  838.     }
  839.     fprintf(fp, "\n");
  840. }
  841.  
  842. /* Prints the list of files, titles, and sizes into the index file.
  843. */
  844.  
  845. void printfilelist(filep, fp)
  846.      struct file *filep;
  847.      FILE *fp;
  848. {
  849.     int i;
  850.  
  851.     i = 0;
  852.     offsets[FILELISTPOS] = ftell(fp);
  853.         while (filep != NULL) {
  854.         addtofilehashlist(i++, ftell(fp));
  855.                 fprintf(fp, "%s \"%s\" %d\n", ruleparse(filep->filename),
  856.                 filep->title, filep->size);
  857.                 filep = filep->next;
  858.         }
  859. }
  860.  
  861. /* Prints the list of file offsets into the index file.
  862. */
  863.  
  864. void printfileoffsets(fp)
  865.      FILE *fp;
  866. {
  867.     int i;
  868.  
  869.     offsets[FILEOFFSETPOS] = ftell(fp);
  870.     for (i = 0; getfilenum(i) != 0; i++)
  871.         fprintf(fp, "%016li", getfilenum(i));
  872. }
  873.  
  874. /* Takes a number and prints it to a file using the simple
  875. ** accordion scheme of storing numbers.
  876. */
  877.  
  878. void compress(num, fp)
  879.      int num;
  880.      FILE *fp;
  881. {
  882.         int i, r;
  883.         static char s[8];
  884.  
  885.         i = 0;
  886.         while (num) {
  887.                 r = num % 128;
  888.                 num /= 128;
  889.                 s[i++] = r;
  890.         }
  891.         while (i-- >= 0)
  892.                 fputc(s[i] | (i ? 128 : 0), fp);
  893. }
  894.  
  895. /* Prints out the decompressed values in an index file.
  896. */
  897.  
  898. void decompress(fp)
  899.      FILE *fp;
  900. {
  901.         int c, x, inword;
  902.     long pos;
  903.         char line[MAXSTRLEN], header[MAXHEADCHARS + 1];
  904.  
  905.     readoffsets(fp);
  906.     fseek(fp, 0, 0);
  907.         inword = 1;
  908.  
  909.         while (1) {
  910.                 c = fgetc(fp);
  911.                 ungetc(c, fp);
  912.                 if (c == '#') {
  913.                         fgets(line, MAXSTRLEN, fp);
  914.             printf("%s", line);
  915.                         continue;
  916.                 }
  917.                 else {
  918.                         fgets(header, MAXHEADCHARS + 1, fp);
  919.             printf("%s", header);
  920.                         break;
  921.                 }
  922.         }
  923.  
  924.         while ((c = fgetc(fp)) != EOF) {
  925.                 if (c == ':' && inword) {
  926.                         inword = 0;
  927.                         putchar(c);
  928.                 }
  929.                 if (inword)
  930.                         putchar(c);
  931.                 else {
  932.                         x = 0;
  933.                         do {
  934.                                 c = fgetc(fp);
  935.                 pos = ftell(fp);
  936.                 if (pos == offsets[STOPWORDPOS]) {
  937.                     putchar('\n');
  938.                     while (fgets(line, MAXSTRLEN, fp)
  939.                     != NULL)
  940.                         printf("%s", line);
  941.                         return;
  942.                 }
  943.                                 if (c == 0) {
  944.                                         putchar('\n');
  945.                                         inword = 1;
  946.                                         break;
  947.                                 }
  948.                                 x *= 128;
  949.                                 x += c & 127;
  950.                         } while (c & 128);
  951.                         if (x)
  952.                                 printf(" %d", x);
  953.                 }
  954.         }
  955. }
  956.  
  957. /* Parses lines according to the ReplaceRules directives.
  958. */
  959.  
  960. char *ruleparse(line)
  961.      char *line;
  962. {
  963.         char rule[MAXSTRLEN];
  964.         static char tmpline[MAXSTRLEN], newtmpline[MAXSTRLEN];
  965.         static char line1[MAXSTRLEN], line2[MAXSTRLEN];
  966.         struct swline *tmplist;
  967.  
  968.     if (replacelist == NULL)
  969.         return line;
  970.  
  971.         tmplist = replacelist;
  972.         strcpy(tmpline, line);
  973.         while(1) {
  974.         if (tmplist == NULL)
  975.             return tmpline;
  976.                 strcpy(rule, tmplist->line);
  977.         tmplist = tmplist->next;
  978.         if (tmplist == NULL)
  979.             return tmpline;
  980.                 if (rule == NULL) {
  981.                         replacelist = tmplist;
  982.                         return tmpline;
  983.                 }
  984.                 else {
  985.                         if (lstrstr(rule, "replace")) {
  986.                                 strcpy(line1, tmplist->line);
  987.                 tmplist = tmplist->next;
  988.                                 strcpy(line2, tmplist->line);
  989.                 tmplist = tmplist->next;
  990.                                 strcpy(newtmpline, (char *) replace(tmpline,
  991.                                 line1, NOWORD));
  992.                                 strcpy(newtmpline, (char *) replace(newtmpline,
  993.                                 NOWORD, line2));
  994.                         }
  995.                         else if (lstrstr(rule, "append")) {
  996.                 sprintf(newtmpline, "%s%s", tmpline,
  997.                 tmplist->line);
  998.                 tmplist = tmplist->next;
  999.             }
  1000.             else if (lstrstr(rule, "prepend")) {
  1001.                 sprintf(newtmpline, "%s%s", tmplist->line,
  1002.                 tmpline);
  1003.                 tmplist = tmplist->next;
  1004.             }
  1005.             strcpy(tmpline, newtmpline);
  1006.                 }
  1007.         }
  1008. }
  1009.